<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  
  <title>
    BLE Security Manager | 朝雨绫萧的博客
  </title>
  <meta content="width=device-width, initial-scale=1" name="viewport">
  <meta name="theme-color" content="#4184f3">
  
  
  <link href="/image/favicon.png" rel="icon" />
  

  
<link rel="stylesheet" href="/css/highlight.light.css">

  
<link rel="stylesheet" href="/css/prism-customize.css">

  
<link rel="stylesheet" href="/css/nav-icon.css">

  
<link rel="stylesheet" href="/css/waves.min.css">

  
<link rel="stylesheet" href="/css/jquery.tocify.css">

  
<link rel="stylesheet" href="/css/main.css">

  
<link rel="stylesheet" href="/css/nav-indicator.css">

  
<link rel="stylesheet" href="/css/twikoo.css">

  
<link rel="stylesheet" href="/css/search.css">

  
  

  

  </meta>
  </meta>
  <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>
  
<script src="/js/comment.js"></script>

  
<script src="/js/copy.js"></script>

<meta name="generator" content="Hexo 5.4.0"></head>

	<body>
		<header>
			<!-- cover image or sth. -->
		</header>
		<div id="main" class="m-scene">
			
<div class="nav-wrapper" id="header">

    <div class="container">
        <nav>
            
            
            <div class="logo wave">
                <a href="/" id="logo">
                    朝雨绫萧的博客
                </a>
            </div>

            

            <div class="nav-toggle-icon" >
                <div class="material-hamburger">
                    <span>
                    </span>
                    <span>
                    </span>
                    <span>
                    </span>
                </div>
            </div>

            <div class="menu-wrapper">
                <div class="nav-indicator">
                </div>
                <ul class="menus">
                    
                     
                        <li>
                            <a class="wave " href="/">
                                首页
                            </a>
                        </li>
                     
                        <li>
                            <a class="wave " href="/archives">
                                归档
                            </a>
                        </li>
                     
                        <li>
                            <a class="wave " href="/about">
                                关于
                            </a>
                        </li>
                     
                        <li>
                            <a class="wave " href="/message">
                                留言
                            </a>
                        </li>
                     
                        <li>
                            <a class="wave " href="/search">
                                搜索
                            </a>
                        </li>
                     
                    
                   
                </ul>
            </div>

        </nav>
    </div>
</div>


				<div class="container content">
					<div class="scene_element scene_element--fadein">
						<div class="row">
  <div class="main main-article">
    <article>

      
        <header class="post-header no-cover">
      
        </header>

      <!-- 标题 -->
      <h1 class="post-title">
        BLE Security Manager
      </h1>

      <section class="post-info post-info-bottom">

        <!-- 发布时间 -->
        <span class="post-date">
          <span class="post-date-text">
            发布于: 2021-02-28
          </span>
        </span>
        
        <!-- 分类 -->
        
          <span class="post-category">分类:
            <a class="article-category-link" href="/categories/BLE/">BLE</a>
          </span>
        

        <!-- 标签 -->
        
          <span class="post-tags">
            <ul class="post-tag-list" itemprop="keywords"><li class="post-tag-list-item"><a class="post-tag-list-link" href="/tags/BLE/" rel="tag">BLE</a></li></ul>
          </span>
        

        <!-- 阅读量统计 -->
        

      </section>

      <!-- 正文 -->
      <section class="post-content">
        <h1 id="安全管理层（Security-Manager）"><a href="#安全管理层（Security-Manager）" class="headerlink" title="安全管理层（Security Manager）"></a>安全管理层（Security Manager）</h1><p>安全管理层定义了 BLE 通信两端设备的配对方法和密钥分发的工作模式，提供了一系列加密算法，为 BLE 通信提供了加密、认证等安全保障。它与 GAP 层密切相关，关于安全需求的一些配置是在 GAP 层中完成的。</p>
<h2 id="BLE通信面临的威胁"><a href="#BLE通信面临的威胁" class="headerlink" title="BLE通信面临的威胁"></a>BLE通信面临的威胁</h2><p><strong>窃听</strong></p>
<p>考虑常规的 BLE 通信，一端是手机，一端是 BLE 设备。假如二者没有进行认证加密，那么在通信开始之前，在附近开启一个 BLE Sniffer，就可以看到手机与 BLE 设备之间的连接后的通信数据明文。</p>
<p><strong>MITM攻击</strong></p>
<p>MITM（Man in the Middle）中间人攻击是指第三方设备混入 BLE 通信链路之间，伪造通信数据迷惑双方。假如设备 A 和设备 B 在通信之始，设备 M 注意到二者要进行通信，设备 M 截取设备 A 发起的连接请求，伪装成设备 B 跟其建立连接进行通信，通信完毕后再伪装成设备 A 向设备 B 发起连接请求，建立连接后重复设备 A 在前面发送的数据。这样设备 A 就一直以为在跟设备 B 进行通信，设备 B 也同样，却不知二者中间还藏着一个第三者。</p>
<p><strong>追踪</strong></p>
<p>BLE 广播包中包含了设备地址，使用 Android 手机，安装一个 BLE 扫描 App，就可以获取周边正在广播设备的地址信息。设备地址是不会轻易改变的，所以跟踪设备的广播信息，就可以跟踪这个设备。更形象的描述，一个用户带着一个运动手环，攻击者可以检测附近的广播，一路追踪这个手环的移动。解决这个问题需要对设备地址进行特殊处理，即将设备地址包装成随机地址。iOS 系统的 BLE 默认开启随机地址，过几十分钟就变换一次设备地址。</p>
<h2 id="BLE的安全措施"><a href="#BLE的安全措施" class="headerlink" title="BLE的安全措施"></a>BLE的安全措施</h2><p>BLE 提供三种等级的安全措施：</p>
<ul>
<li>No Security（无保护）</li>
<li>Unauthenticated no MITM protection（不认证、不能抵御MITM（也不能抵御窃听）的保护）</li>
<li>Authenticated MITM protection（做认证、能够抵御MITM（也能够抵御窃听）的保护）</li>
</ul>
<p>在 No Security 情况下，设备不用进行加解密计算，内部计算少对功耗有益，操作也会更加方便。由于没有生成任何密钥，所以这种方式不能使用加密和绑定等功能。</p>
<p>第二种保护方式，BLE 主从设备之间不进行认证过程。设备会将认证密码设置0，两端设备无需交换这个密码，自动进行生成密钥的操作。由于密码是公开的，可以推算出设备端生成的密钥，因此 Sniffer 是可以看到通信过程中的数据明文的，即无法避免窃听和 MITM 的威胁。但是，这个方式仍然会产生密钥，可以进行后续的加密和绑定动作，假如 Sniffer 未在配对之始就跟踪通信链路，就无法破解通信链路，这也能提供一定程度的安全保护。对于类似蓝牙耳机这种没有输入输出途径的设备，只能选择这种保护方式。假如一个设备需要绑定功能，不在意数据安全，也可以选择这个方式。</p>
<p>第三种为最强保护等级，既做认证又做加密。所谓认证，是指一方提供密码，在另一方输入并回传，如果密码匹配则为通过认证。通过认证的设备，就可以相互交换各自的密钥。二者之间的通信以密钥进行加解密，第三方设备没有密钥就无法获知数据明文。这种情况下的BLE通信，使用 Sniffer 看不到通信数据明文，仅能识别出部分帧格式。假如给 Sniffer 提供了认证密码，Sniffer 就能够攻破加密链路，解密出数据明文。</p>
<h2 id="配对（Pairing）"><a href="#配对（Pairing）" class="headerlink" title="配对（Pairing）"></a>配对（Pairing）</h2><p>实现上述三种保护方式，需要涉及一系列相关工作和参数：配对绑定的需求、设备的输入输出能力、生成密钥的过程、交换密钥的过程、加密算法选择、密钥种类等等。BLE 将这些过程，组织成一个专门的行为，即配对（Pairing）。从宏观上看，配对就是手机端输入一串密码，与 BLE 设备建立关联，从协议层面上看，配对就是规定了密钥的生成方法和分发流程，并顺带把链路给加个密。</p>
<h3 id="配对的流程"><a href="#配对的流程" class="headerlink" title="配对的流程"></a>配对的流程</h3><p>配对分三个阶段：</p>
<ul>
<li>交换配对特征</li>
<li>生成短期密钥 STK（Short Term Key）</li>
<li>生成长期密钥 LTK（Long Term Key）并分发</li>
</ul>
<p>其中前两个阶段为必须阶段，第三个阶段非必须。经过第二个阶段，BLE 的通信链路根据加密需求进行加密或者不加密。如果加密，则第三个阶段就可以生成一系列特殊作用的密钥，并分发出去（其实就是主从机将自己的密钥交给对方）。如果不加密，则无需进行第三个阶段。</p>
<h3 id="IO-Capability"><a href="#IO-Capability" class="headerlink" title="IO Capability"></a>IO Capability</h3><p>配对特征包括：输入输出能力（IO Capability），OOB 认证数据，密钥长度等。其中 IO 能力最常用也最关键，其他参数通常保持默认即可。IO Capability 是指 BLE 设备具有何种输入输出能力，BLE 对 IO 能力进行了枚举，抽象出 3 种输入能力和 2 种输出能力：</p>
<ul>
<li>Display Only</li>
<li>Display，YesNO</li>
<li>Keyboard Only</li>
<li>NO Input，No Output</li>
<li>Keyboard，Display</li>
</ul>
<p>这个参数影响了可以选择的安全保护方式，假如两个设备一个是 Keyboard &amp; Display，一个是 No Input &amp; No Output，它们就无法进行密码输入，也就无法选择 Authenticated MITM protection 这种保护方式。</p>
<h3 id="配对方法"><a href="#配对方法" class="headerlink" title="配对方法"></a>配对方法</h3><p>两端设备的 IO 能力不同，在第二阶段采用的生成密钥的方法也不同，BLE 协议规定了三种生成密钥的方法，也称为“配对方法”：</p>
<ul>
<li>Just Works</li>
<li>Passkey Entry</li>
<li>OOB（Out of Band）</li>
</ul>
<p>Passkey Entry 方法以一个 6 字节密码为初始密码，执行加密动作。由于初始密码为随机生成，因而能够保证后续加密行为的安全性。这种方法产生的链路是认证的（Authenticated）。在实际使用中，需要设备具有输出能力用以显示密码，在手机端输入密码，或者反过来设备端有一个输入键盘，手机端提供密码。</p>
<p>Just Works 方法无需输入密码，两端设备仍然执行加密动作，但是初始密码设为 0。这种方法产生的链路是未认证的（Unauthenticated）。在实际使用中，Just Works 在配对时候手机屏幕会有弹窗，用户仅需要点一下确认即可。</p>
<p>OOB 是指利用第三方途径，比如NFC或者WIFI，将Passkey传输给对方。只要这个第三方途径足够安全，就能够保证 Passkey 的安全，从而避免攻击设备截获 Passkey。这个方案受限于第三方途径的匮乏以及操作的复杂性，使用比较少。</p>
<h3 id="配对请求（Pairing-Request）"><a href="#配对请求（Pairing-Request）" class="headerlink" title="配对请求（Pairing Request）"></a>配对请求（Pairing Request）</h3><p>如果配对是由主机发起，则主机向从机发起配对请求。如果是由从机发起，则从机先向主机发出一个 Security Request，请求发起安全管理流程，主机收到后再发起配对请求。<br>配对请求中包含以下内容：</p>
<ul>
<li>IO Capability：输入输出能力</li>
<li>OOB Data Flag：是否采用 OOB（如果置位，则覆盖AuthReq Flag）</li>
<li>AuthReq Flag：是否需要绑定、MITM保护</li>
<li>Encryption Key Size：密钥长度</li>
<li>Initiator Key Distribution：发起者要求哪些密钥需要分发</li>
<li>Responder Key Distribution：响应者要求哪些密钥需要分发</li>
</ul>
<p>主从两端经过配对请求和响应以后，就能够获知对方的 IO 能力和是否需要认证，从而选择一个合适的配对方法。<br>至此配对的第一阶段结束，下面进入第二阶段：生成 STK，加密链路。</p>
<h3 id="生成STK（Short-Term-Key）"><a href="#生成STK（Short-Term-Key）" class="headerlink" title="生成STK（Short Term Key）"></a>生成STK（Short Term Key）</h3><p>先介绍一下临时密钥 TK（temporary Key），顾名思义，就是一个临时用的密钥。对于 Passkey Entry 方法，假如 6 字节的密码为 123456，注意这个密码是十进制，将其转成十六进制为 0x01E240，那么对应生成的 TK=0x00…001E240，TK 长度为 128bit（16字节），前面补足 0。对于 Just Works 方法，TK=0x00…0，长度也是 128bit。有了 TK，可以使用 BLE 协议栈的随机算法生成几个随机序列：Mconfirm，Mrand，Sconfirm，Srand。其中前缀 M 表示 Master，S 表示 Slave，后缀 confirm 表示确认命令，rand 表示随机命令。这四个随机序列长度均为 128bit。</p>
<p>配对第二阶段，主机端（Master）先生成 Mconfirm 和 Mrand，从机端（Slave）生成 Sconfirm 和 Srand，然后主机将自己的 Mconfirm 发给从机，从机将自己的 Sconfirm 发给主机。而后主从分别将自己的 rand 发给对方，并根据 rand 和 TK 值计算出 confirm 序列，这个序列如果跟刚刚交换的对方的 confirm 序列相等，则通过校验，否则报错。如果双方都通过校验，则根据 TK、Srand 和 Mrand 三个序列生成出一个新的序列，称为 STK。</p>
<h3 id="密钥分发（Distribution）"><a href="#密钥分发（Distribution）" class="headerlink" title="密钥分发（Distribution）"></a>密钥分发（Distribution）</h3><p>在安全管理的规划里，有多种密钥承担着不同的工作，除了STK，还包括如下密钥：</p>
<ul>
<li>身份解析密钥 IRK（Identity Resolving Key）：用于解析随机地址</li>
<li>连接前面密钥 CSRK（Connection Signature Resolving Key）：用于签名和验证签名</li>
<li>长期密钥 LTK（Long Term Key）：用于记录加密后的链接</li>
<li>辅助密钥 EDIV（Encrypted Diversifier）：用于识别LTK，每次刷新LTK都会重新生成</li>
<li>随机数 Rand（Random Number）：用于识别LTK，每次刷新LTK都会重新生成</li>
</ul>
<p>设备地址经过 IRK 加密可以变成随机地址（私有地址），这样能够解决“追踪”的威胁。另一端设备利用 IRK 可以将随机地址还原成原始地址。</p>
<p>CSRK 用于签名类的问题。</p>
<p>LTK 存在于绑定信息中，而绑定信息会存于 Flash，所以 LTK 能够长期保持。假如两个设备已经绑定，断开后重新连接，就会去校验 LTK 信息。LTK 如此重要，甚至提供了 EDIV 和 Rand 来增加它的安全性。<br>这些密钥大多需要 STK 作为种子来生成，主从两端生成这些密钥并相互交换，就完成了配对的第三阶段。</p>
<h3 id="绑定（Bonding）"><a href="#绑定（Bonding）" class="headerlink" title="绑定（Bonding）"></a>绑定（Bonding）</h3><p>经过了配对过程，主从两端都获得了几个密钥，将这些密钥以及一些必要的额外信息（比如对方设备地址）打包存到 Flash 中，这个过程就叫绑定。简单的讲，配对是生成密钥，绑定是保存密钥。这两个行为在时序上前后关联，绑定前肯定需要经过配对，配对结束后可以选择不绑定。</p>
<h3 id="重连"><a href="#重连" class="headerlink" title="重连"></a>重连</h3><p>主从两端绑定以后，各自保存了绑定信息，那么下次重连，无需再次输入 Passkey，即进入认证状态。如果从机端采用了 HID Profile，甚至可以实现设备自动重连，只有手机发现从机在附近广播，就自动重连它。假如一端设备中的绑定信息受损，比如手机端的绑定信息被意外清除，那么在下次连接时候就需要重新进行配对、绑定流程。</p>
<h3 id="加密（Encryption）"><a href="#加密（Encryption）" class="headerlink" title="加密（Encryption）"></a>加密（Encryption）</h3><p>经过了配对，BLE 通信链路就被加密，但是这种加密是基于 Passkey 一路加密而来，假如 Sniffer 获得了 Passkey，就能够翻译出加密链路上通行的数据。</p>

      </section>

    </article>
    
    


    <!-- 版权声明 -->
    <div class="post-copyright">
	<div>
		<strong>本文作者：</strong>
		<span>
			朝雨绫萧
		</span>
	</div>
	<div>
		<strong>本文链接：</strong>
		<a href="http://zzylxx.gitee.io/BLE SM">
			http://zzylxx.gitee.io/BLE SM
		</a>
	</div>
	<div>
		<span>欢迎任何形式的转载，但请务必注明出处。</span>
	</div>
	<div>
		<span>由于笔者水平有限，如果文章或代码有表述不当之处，还请不吝赐教。</span>
	</div>
</div>


<style>
	.post-copyright {
		background-color: #fff;
		/* box-shadow: 0px 0px 1px 1px rgba(0, 0, 0, 0.05); */
		box-shadow: 0 6px 30px -10px rgba(0, 0, 0, 0.1);
		display: block;
		margin: 20px auto;
		margin-bottom: 15px;
		padding: 10px;
		font-size: 15px;
		color: #2e2d2d;
		word-break: break-all;
		line-height: 1.8;
	}


	.post-copyright a {
		color: #2e2d2d;
		border-bottom: 1px solid #999;
	}

	.post-copyright a:hover {
		color: #2e2d2d;
		border-bottom: 1px solid #000;
	}
</style>

    <!-- comments -->
    <div class="comments">
    <h3 id="commenttitle" style="margin-top: 20px;margin-left: 10px;">评论区</h3>
    <div id="tcomment"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/twikoo@1.0.0/dist/twikoo.all.min.js"></script>
<script>twikoo.init({ envId: 'twikoo-1gx61ki809c44dc7', el: '#tcomment' })</script>

    <div class="right-icon">
      <div id="to-valine" class="right-icon-item">
        <a href="#commenttitle">评论</a>
      </div>
    </div>

  </div>


  <aside>
    <div class="aside-wrap">
    
        <section class="widget-wrap">
    <h3 class="widget-title">简介</h3>
    <div class="widget">
        <div class="notice">
            <img class="notice-img" src="/image/head_portrait.jpg">
            <p>路漫漫其修远兮，<br>吾将上下而求索!<br></p>
            
            <p class="notice-item">
                <!-- github -->
                <span><a target="_blank" href="https://github.com/qgyhd1234"><img src="https://shuxhan-imgbed.oss-cn-hangzhou.aliyuncs.com/img/20210108165043.jpg" alt="Github"></a></span>
                <!-- juejin -->
                <!-- <span><a target="_blank" href=""><img src="https://shuxhan-imgbed.oss-cn-hangzhou.aliyuncs.com/img/20210108165800.png" alt="掘金社区"></a></span> -->
                <!-- zhihu -->
                <!-- <span><a target="_blank" href=""><img src="https://shuxhan-imgbed.oss-cn-hangzhou.aliyuncs.com/img/20210108172745.ico" alt="知乎"></a></span> -->
                <!-- csdn -->
                <!-- <span><a target="_blank" href=""><img src="https://shuxhan-imgbed.oss-cn-hangzhou.aliyuncs.com/img/20210108172932.ico" alt="CSDN"></a></span> -->
            </p>

            <ul class="statistics">
                <li>
                    <span>文章</span>
                    <a href="./archives">7</a>
                </li>
                <li>
                    <span>字数</span>
                    <a>9.7k</a>
                </li>
                <li>
                    <span>访客</span>
                    <a id="busuanzi_value_site_uv"></a>
                </li>
                
                
            </ul>

            <div id="follow" class="button">
                <a target="_blank" href="https://github.com/shuxhan">关注</a>
            </div>
        </div>
    </div>
</section>

    
        
  <section class="widget-wrap">
    <h3 class="widget-title">文章分类</h3>
    <div class="widget">
      <div class="categories-list">
        
           
            
              <a class="category-list-item" href="/categories/BLE">
                <span class="category-list-link">BLE</span>
                <span class="category-list-number">(7)</span>
              </a>
            
          
        
      </div>
    </div>
  </section>


    
        
  <div class="widget-wrap">
    <h3 class="widget-title">标签</h3>
    <div class="widget">
      <ul class="tag-list" itemprop="keywords"><li class="tag-list-item"><a class="tag-list-link" href="/tags/BLE/" rel="tag">BLE</a></li></ul>
    </div>
  </div>


    
        
  <div class="widget-wrap">
    <h3 class="widget-title">最新文章</h3>
    <div class="widget">
      <ul class="recent-posts">
        
          <li>
            <a href="/2021/02/28/GAP%E5%8F%82%E6%95%B0%E8%AE%BE%E7%BD%AE/">BLE GAP参数设置</a>
          </li>
        
          <li>
            <a href="/2021/02/28/BLE%E5%B9%BF%E6%92%AD%E5%92%8C%E6%89%AB%E6%8F%8F%E5%93%8D%E5%BA%94/">BLE 广播和扫描响应</a>
          </li>
        
          <li>
            <a href="/2021/02/28/BLE%20%E8%BF%9E%E6%8E%A5/">BLE 连接</a>
          </li>
        
          <li>
            <a href="/2021/02/28/BLE%20SM/">BLE Security Manager</a>
          </li>
        
          <li>
            <a href="/2021/02/28/BLE%20GATT/">BLE GATT</a>
          </li>
        
      </ul>
    </div>
  </div>

    
        
  <section class="widget-wrap">
    <h3 class="widget-title">归档</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/02/">二月 2021</a></li></ul>
    </div>
  </section>


    
    
</div>


    <!-- 目录 -->
    
  </aside>
  
</div>

					</div>
				</div>

				<!-- 返回顶部按钮 -->
				<div class="right-icon">
					<div id="to-top" class="right-icon-item">
						<a>
							<span class="top-left"></span>
							<span class="top-right"></span>
						</a>
					</div>
				</div>
		</div>
		<footer class="footer">

    <div class="copyright-wrap">
      <span>&copy; 2021-2021 朝雨绫萧</span>
      <span id="timeDate">载入天数...</span><span id="busuanzi_container_site_pv">
      总访问量<span id="busuanzi_value_site_pv"></span>次
    </span>
    </div>
    
    
    <!-- <span id="busuanzi_container_site_uv">
      ，本站访客数<span id="busuanzi_value_site_uv"></span>人次
    </span> -->
    
</footer>

<script>
    var now = new Date();
    function createtime() {
      var grt = new Date("2/27/2021 16:12:00");//此处修改你的建站时间或者网站上线时间 
      now.setTime(now.getTime() + 250);
      days = (now - grt) / 1000 / 60 / 60 / 24; dnum = Math.floor(days);
      document.getElementById("timeDate").innerHTML = "本站已安全运行 " + dnum + " 天 ";
    }
    setInterval("createtime()", 1000);
</script>

<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

<script src="/lib/jquery.js"></script>


<script src="/lib/waves.js"></script>


<script src="/lib/jquery-ui.js"></script>


<script src="/lib/jquery.tocify.js"></script>


<script src="/js/main.js"></script>


			
<style>
  .copy-btn {
    display: inline-block;
    padding: 6px 12px;
    font-size: 13px;
    font-weight: 500;
    line-height: 20px;
    color: rgb(206, 206, 206);
    white-space: nowrap;
    vertical-align: middle;
    cursor: pointer;
    border-radius: 3px;
    user-select: none;
    outline: 0;
  }

  .copy-btn:hover {
    color: #888
  }

  .highlight-wrap .copy-btn {
    padding: 2px 6px;
    position: absolute;
    right: 10px;
    top: 1px;
    z-index: 1;
  }



  .highlight-wrap {
    position: relative;
  }

  #copysuccess {
    width: 200px;
    height: 75px;
    position: fixed;
    right: 50%;
    margin-right: -100px;
    top: 40%;
    margin-top: -40px;
    color: #fff;
    font-weight: 600;
    background: #444444d8;
    display: none;
    z-index: 99999;
    border-radius: 10px;
    text-align: center;
    line-height: 30px;
    padding-top: 10px;
    user-select: none;
  }
</style>

<script>
  addLoadEvent(() => {
    $('.highlight').each(function (i, e) {
      var $wrap = $('<div>').addClass('highlight-wrap')
      $(e).after($wrap)
      $wrap.append($('<div>').addClass('copy-btn').append('复制代码').on('click', function (e) {
        var copysuccess = document.getElementById('copysuccess');
        copysuccess.style.display = 'block'
        setTimeout(function () {
          copysuccess.style.display = 'none'
        }, 2000)
        var code = $(this).parent().find(".code")[0].innerText
          
                var ta = document.createElement('textarea')
        document.body.appendChild(ta)
        ta.style.position = 'absolute'
        ta.style.top = '0px'
        ta.style.left = '0px'
        ta.value = code
        ta.select()
        ta.focus()
        var result = document.execCommand('copy')
        document.body.removeChild(ta)
          
                  if (result) $(this).text('复制成功')
            else $(this).text('复制失败')
              
                $(this).blur()
      })).on('mouseleave', function (e) {
        var $b = $(this).find('.copy-btn')
        setTimeout(function () {
          $b.text('复制代码')
        }, 1000)
      }).append(e)
    })
  })
</script>

				<div id="copysuccess">复制成功<br>欢迎阅读文章~</div>
	</body>

</html>

<script>
	$('#to-top').click(function () { $('html,body').animate({ scrollTop: '0px' }, 500); return false; });
</script>